#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_err.h"

#include "driver/i2c.h"
#include "oled.h"

#define GPIO_KEY 0
#define ACK_CHECK_EN 0x1		   /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0		   /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0				   /*!< I2C ack value */
#define NACK_VAL 0x1			   /*!< I2C nack value */
#define LAST_NACK_VAL 0x2		   /*!< I2C last_nack value */

static xQueueHandle gpio_evt_queue = NULL;

void IIC_Write_Data(uint8_t dat1,uint8_t dat2,const uint8_t *data, uint16_t len)
{
	i2c_cmd_handle_t hi2c = i2c_cmd_link_create();
	i2c_master_start(hi2c);
	i2c_master_write_byte(hi2c, dat1, ACK_CHECK_EN);
	i2c_master_write_byte(hi2c, dat2, ACK_CHECK_EN);
	for(;len>0;len--){
		i2c_master_write_byte(hi2c, *data++, ACK_CHECK_EN);
	}
	i2c_master_stop(hi2c);
	i2c_master_cmd_begin(I2C_NUM_0, hi2c, 1000 / portTICK_RATE_MS);
	i2c_cmd_link_delete(hi2c);
}

static void task1(void *arg)
{
    char *showStr;
    i2c_config_t i2c_conf;
    i2c_conf.mode = I2C_MODE_MASTER;
    i2c_conf.sda_io_num = 2;
    i2c_conf.sda_pullup_en = 1;
    i2c_conf.scl_io_num = 14;
    i2c_conf.scl_pullup_en = 1;
    i2c_conf.clk_stretch_tick = 300; // 300 ticks, Clock stretch is about 210us, you can make changes according to the actual situation.

    ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, i2c_conf.mode));
    ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &i2c_conf));

    Oled_Init(0x78,IIC_Write_Data);

    showStr = malloc(30);
    OLED_ShowString(0, 0, "Free Mem", 16);
    OLED_ShowString(0, 4, "Free min Mem", 16);

    while (1)
    {
        printf("Update Free Men\n");
        sprintf(showStr, "%d Byte", esp_get_free_heap_size());
        OLED_ShowString(0, 2, showStr, 16);
        sprintf(showStr, "%d Byte", esp_get_minimum_free_heap_size());
        OLED_ShowString(0, 6, showStr, 16);
        vTaskDelay(1000 / portTICK_RATE_MS);
    }
    vTaskDelete(NULL);
}

static void gpio_isr_handler(void *arg)
{
    uint32_t gpio_num = (uint32_t)arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

void Gpio_Init(void){
    gpio_config_t IO_config;
    IO_config.pin_bit_mask = 1UL << GPIO_KEY;
    IO_config.mode = GPIO_MODE_INPUT;
    IO_config.pull_up_en = GPIO_PULLUP_ENABLE;
    IO_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    IO_config.intr_type = GPIO_INTR_NEGEDGE;
    gpio_config(&IO_config);

    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    gpio_install_isr_service(0);
    gpio_isr_handler_add(GPIO_KEY, gpio_isr_handler, (void *)GPIO_KEY);
}

static void task2(void *arg)
{
    uint32_t io_nun;
    char *p;
    Gpio_Init();

    while (1)
    {
        if (xQueueReceive(gpio_evt_queue, &io_nun, portMAX_DELAY))
        {
            if (io_nun == GPIO_KEY)
            {
                printf("malloc: p:");
                p = malloc(1000);
                printf("0x%x\n",(uint32_t)p);
            }
        }
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    xTaskCreate(task1, "task1", 2048, NULL, 20, NULL);
    xTaskCreate(task2, "task2", 2048, NULL, 21, NULL);
}
